package com.loong.order.consumer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.loong.common.enumerate.OrderStatus;
import com.loong.common.rabbitmq.consumer.BaseConsumer;
import com.loong.common.rabbitmq.dto.OrderDTO;
import com.loong.common.rabbitmq.dto.base.CommonEventDto;
import com.loong.global.constant.MQConstant;
import com.loong.order.handler.OrderHandler;
import com.loong.order.model.OrderBase;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Description: mq -》 db 服务
 * @Author: hzp
 * @Date: 2020-12-29 14:37
 */
@Slf4j
@Component
public class OrderDBConsumer extends BaseConsumer {

    @Resource
    private   OrderHandler orderHandler;

    private static Long nowSaveDbStaticTime = 0L ;
    private static Long nowUpdateDbStaticTime = 0L ;
    private static Long nowDeleteDbStaticTime = 0L ;
//    private static Long deadNowStaticTime = 0L;
    private static final List<OrderDTO> saveDbDataList = new ArrayList<>();
    private static final List<OrderDTO> updateDbDataList = new ArrayList<>();
    private static final List<OrderDTO> deleteDbDataList = new ArrayList<>();
//    private static final List<OrderDTO> dataDbDeadList = new ArrayList<>();

    /**
     * 用于控制 一次性操作的集合大小
     */
    private static final int size = 20;
    /**
     * 用于不管有没有消息 submitDbTime 时间到了就入库
     */
    private static final int submitTime = 5;




    /**
     * 处理订单队列  DB
     * @param channel 通道
     * @param message 消息对象
     * @throws IOException IOException
     */
    @RabbitListener(queues = {MQConstant.BASE_PREFIX + MQConstant.QUEUE_NAME.ORDER_DB + MQConstant.BASE_SUFFIX.QUEUE}, containerFactory = "defaultRabbitListener")
    public void receiveDbEvent(Channel channel, Message message) throws IOException {
        log.debug("监听到====DB Topic 队列======");
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        byte[] data = message.getBody();
        CommonEventDto<JSONObject> eventDto = JSON.parseObject(new String(data)).toJavaObject(CommonEventDto.class);
        Short eventCode = eventDto.getEventCode();
        OrderDTO orderDTO = eventDto.getData().toJavaObject(OrderDTO.class);
        log.debug("====ES Topic OrderDTO===== {}"+orderDTO);
        //本地缓存 订单信息
        addDataList(eventCode,orderDTO);
        //消费缓存的订单信息
        checkTimeAndExecutor();

        //消息确认
        if(OrderStatus.WAITING_PAYMENT.getCode()!=orderDTO.getOrderBase().getStatus()){
            //已支付 就删除消息
            submitAck(channel, deliveryTag);
        }

    }


    /**
     * 处理死信 DB 队列  主要将规定支付时间内 未支付的订单删除
     * @param channel 通道
     * @param message 消息
     * @throws IOException IOException
     */
    @RabbitListener(queues = {MQConstant.BASE_PREFIX + MQConstant.QUEUE_NAME.DEAD_ORDER_DB + MQConstant.BASE_SUFFIX.QUEUE}, containerFactory = "defaultRabbitListener")
    public void receiveDbDeadEvent(Channel channel, Message message) throws IOException {
        log.debug("监听到====DB Topic 死信队列======");
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        byte[] data = message.getBody();
        CommonEventDto<JSONObject> eventDto = JSON.parseObject(new String(data)).toJavaObject(CommonEventDto.class);
        OrderDTO orderDTO = eventDto.getData().toJavaObject(OrderDTO.class);
        OrderBase orderBase = orderHandler.findOrderBaseById(orderDTO.getOrderBase().getId());
        if(null!=orderBase&&(OrderStatus.WAITING_PAYMENT.getCode()==orderBase.getStatus())){
            //删除DB中的订单
            orderHandler.batchDelete(Arrays.asList(orderDTO));
        }
        submitAck(channel, deliveryTag);
    }

    private void addDataList(short eventCode,OrderDTO orderDTO){
        switch (eventCode){
            case 1:
                //save
                saveDbDataList.add(orderDTO);
                break;
            case 2:
                //update
                updateDbDataList.add(orderDTO);

                break;
            case 3:
                //delete
                deleteDbDataList.add(orderDTO);
                break;
        }
    }

    public  void checkTimeAndExecutor(){
        long nowTime = System.currentTimeMillis();

                if(nowSaveDbStaticTime ==0){
                    nowSaveDbStaticTime = nowTime;
                }
                if((nowTime - nowSaveDbStaticTime)/1000>submitTime&&saveDbDataList.size()>0){
                    eventExecutor("save");
                }else if(saveDbDataList.size()>=size){
                    eventExecutor("save");
                }

                //update
                if(nowUpdateDbStaticTime ==0){
                    nowUpdateDbStaticTime = nowTime;
                }
                if((nowTime - nowUpdateDbStaticTime)/1000>submitTime&&updateDbDataList.size()>0){
                    eventExecutor("update");
                }else if(updateDbDataList.size()>=size){
                    eventExecutor("update");
                }

                //delete
                if(nowDeleteDbStaticTime ==0){
                    nowDeleteDbStaticTime = nowTime;
                }
                if((nowTime - nowDeleteDbStaticTime)/1000>submitTime&&deleteDbDataList.size()>0){
                    eventExecutor("delete");
                }else if(deleteDbDataList.size()>=size){
                    eventExecutor("delete");
                }

    }


    private  void eventExecutor(String type){
        switch (type){
            case "save":
                //save db
                orderHandler.batchSave(saveDbDataList);
                saveDbDataList.clear();
                nowSaveDbStaticTime = 0L;
                break;
            case "update":
                //update db
                orderHandler.batchUpdate(updateDbDataList);
                updateDbDataList.clear();
                nowUpdateDbStaticTime = 0L;
                break;
            case "delete":
                //delete db
                orderHandler.batchDelete(deleteDbDataList);
                deleteDbDataList.clear();
                nowDeleteDbStaticTime = 0L;
                break;
        }
    }



}
